package wish.stages;

import java.util.ArrayList;
import java.util.List;


import org.htmlparser.Node;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.SimpleNodeIterator;

import wish.model.TaggerExtractor;
import wish.regularExpression.MultipleElements;
import wish.regularExpression.RegularExpressionElement;
import wish.regularExpression.SingleElement;
import wish.sequencealignment.ScoreSequenceAlignment;

public class DataUnitLevelExtractionStage {

	private ScoreSequenceAlignment ssa;
	
	public DataUnitLevelExtractionStage(){
		
		ssa = new ScoreSequenceAlignment();
		
	}
	
	public RegularExpressionElement[] generateSubsequence(Node node, int level){
		
		//TODO Generate subsequence.

		NodeList nodeList = getLevelList(node,level);
		
		SimpleNodeIterator iterator = nodeList.elements();
		
		RegularExpressionElement[] ret = new RegularExpressionElement[node.getChildren().size()];
		
		int index = 0;
		
		while (iterator.hasMoreNodes()){
			
			ret[index] = new SingleElement(TaggerExtractor.extractTag(iterator.nextNode()));
			
			index++;
			
		}
		
		return ret;
		
	}
	
	private NodeList getLevelList(Node node, int level) {
		
		NodeList children = node.getChildren();
		
		if (children == null){
			children = new NodeList();
		}
			
		if (level == 1){
			return children;
		}
		
		NodeList ret = new NodeList();
		
		SimpleNodeIterator iterator = children.elements();
		
		while(iterator.hasMoreNodes()){
			ret.add(getLevelList(iterator.nextNode(), level-1));
		}
		
		return ret;
		
	}

	public RegularExpressionElement[] generateRegularExpression(List<RegularExpressionElement[]> subsequence){
		
		List<RegularExpressionElement[]> noDuplicates = removeDuplicates(subsequence);
		
		List<RegularExpressionElement[]> starsRegularExpression = generateStars(noDuplicates);
		
		List<RegularExpressionElement[]> starsNoDuplicates = removeDuplicates(starsRegularExpression);
		
		RegularExpressionElement[] regex = findOptionalAndDisjunctiveData(starsNoDuplicates);
		
		//TODO Generate regularExpression...
		
		return null;
	}

	private RegularExpressionElement[] findOptionalAndDisjunctiveData(
			List<RegularExpressionElement[]> starsNoDuplicates) {
		
		RegularExpressionElement[] current = starsNoDuplicates.get(0);
		
		for (int i = 1; i < starsNoDuplicates.size(); i++) {
			
			current = findOptionalAndDisjunctiveData(current,starsNoDuplicates.get(i));
			
		}
		
		return current;
		
	}

	private RegularExpressionElement[] findOptionalAndDisjunctiveData(RegularExpressionElement[] current,RegularExpressionElement[] next) {
	
		return ssa.align(current, next);
				
	}

	private List<RegularExpressionElement[]> generateStars(List<RegularExpressionElement[]> subsequence) {
		
		List<RegularExpressionElement[]> ret = new ArrayList<RegularExpressionElement[]>();
		
		for (RegularExpressionElement[] strings : subsequence) {
			
			ret.add(generateStars(strings));
			
		}
		
		return ret;
		
	}

	private RegularExpressionElement[] generateStars(RegularExpressionElement[] strings) {
		
		ArrayList<RegularExpressionElement> ret = new ArrayList<RegularExpressionElement>();
		
		RegularExpressionElement actual = strings[0];
		
		int c = 1;
		
		for (int i = 1; i < strings.length; i++) {
			
			if (!actual.equals(strings[i])){
				
				if(c > 1){
					
					actual = new MultipleElements(actual);
					
				}
				
				ret.add(actual);
				
				actual = strings[i];
				
			}else{
				
				c++;
			
			}
			
		}
		
		return ret.toArray(new RegularExpressionElement[0]);
	}

	private List<RegularExpressionElement[]> removeDuplicates(List<RegularExpressionElement[]> subsequence) {
		
		ArrayList<RegularExpressionElement[]> ret = new ArrayList<RegularExpressionElement[]>(){
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			public boolean contains(Object subsequence){
				
				RegularExpressionElement[] subsequ= (RegularExpressionElement[])subsequence;
				
				for (RegularExpressionElement[] strings : this) {
					
					if (equals(strings,subsequ)){
						return true;
					}
					
				}
				
				return false;
			}

			private boolean equals(RegularExpressionElement[] l1, RegularExpressionElement[] l2) {
				
				if (l1.length != l2.length){
					return false;
				}
				
				for (int i = 0; i < l2.length; i++) {
					
					if (!l1[i].equals(l2[i])){
						return false;
					}
					
				}
				
				return true;
			}
		};
		
		for (RegularExpressionElement[] strings : subsequence) {
		
			if (!ret.contains(strings)){
				ret.add(strings);
			}
			
		}
		
		return ret;
	}
	
}
